package com.hxw.sample.opengl30;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;

import com.hxw.sample.opengl30.uitls.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 *
 * 相比于V1，新增了黑白的特效
 * 渲染纹理
 * 黑白特效
 *
 */
public class TextureRenderV2WB implements GLSurfaceView.Renderer {

    //顶点绘制脚本
    private static final String vertex_shader =
            "attribute vec4 aPosition;" +//顶点坐标，我们需要在Java获取到这个值并赋值
            "attribute vec2 aTexCoord;"+//纹理坐标,和顶点坐标对应,通过该值才能知道对纹理上的哪个像素点进行采样并渲染
            "uniform mat4 uTMatrix;"+//变换矩阵
            "varying vec2 vTexCoord;"+
            "void main() {" +
            "  gl_Position = uTMatrix*aPosition;" +//gl_Position是OpenGL内部变量，OpenGL通过该值获取顶点位置
            "  vTexCoord = aTexCoord;"+
            "}";

    //纹理绘制脚本（在顶点的基础上，加上颜色或图像就是纹理）
    private static final String fragment_shader =
            "precision mediump float;"+//浮点数精度
            "uniform sampler2D uSampler;" +   //纹理
            "varying vec2 vTexCoord;"+//纹理坐标
            "void main() {" +
            "    vec4 tc = texture2D(uSampler,vTexCoord);" +//通过纹理坐标在纹理上获取像素点颜色
            "    float color = tc.r *0.3 + tc.g*0.59 + tc.b * 0.11;"+//核心代码
            "    gl_FragColor = vec4(color,color,color,1.0);"+
            "}";

    //一个顶点通常用x,y,z这三个值来表示，但如果是二维，则z可有可无，为0即可
    private final float[] VERTEX ={
            //顶点坐标      纹理坐标

            -1f, 1f  ,0f,   0,0,//左上角
            -1f, -1f ,0f,   0,1,//左下角
            1f , 1f  ,0f,   1,0,//右上角
            1f , -1f ,0f,   1,1 //右下角
    };
    private FloatBuffer mVertexBuffer;

    private int mProgram,mPositionHandle,mTMatrixHandle,mTextCoordHandle,mSamplerHandle;
    private int mTextureId;

    private final float[] mTranslateMatrix = new float[16];//定义一个4x4的变换矩阵

    private final int[] vboIds = new int[1];//VBO

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        final int byteLen = VERTEX.length*4;//字节长度,float占4个字节，所以乘以4
        mVertexBuffer = ByteBuffer.allocateDirect(byteLen)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(VERTEX);
        mVertexBuffer.position(0);

        Matrix.setIdentityM(mTranslateMatrix,0);//设置为单位矩阵
        Matrix.scaleM(mTranslateMatrix, 0, -1f, 1f, 1f);//镜像：左右镜像

        //程序必须在onSurfaceCreated之后加载才行，否则OpenGL环境未就绪是无法正常加载的
        mProgram = ShaderUtil.createProgram(vertex_shader,fragment_shader);

        if (mProgram != 0){
            System.out.println("编译着色器成功");
            mTextureId = uploadTexture();//上传纹理

            mPositionHandle = GLES30.glGetAttribLocation(mProgram,"aPosition");//获取顶点脚本中的aPosition变量的句柄
            GLES30.glEnableVertexAttribArray(mPositionHandle);//设置顶点参数为可用
            mTextCoordHandle = GLES30.glGetAttribLocation(mProgram,"aTexCoord");
            GLES30.glEnableVertexAttribArray(mTextCoordHandle);//设置参数为可用

            mTMatrixHandle = GLES30.glGetUniformLocation(mProgram,"uTMatrix");
            mSamplerHandle = GLES30.glGetUniformLocation(mProgram,"uSampler");

            GLES30.glGenBuffers(1,vboIds,0);//第一个参数为需要创建的VBO数量，第三个参数为0
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,vboIds[0]);//绑定VBO
            GLES30.glBufferData(GLES20.GL_ARRAY_BUFFER,byteLen,mVertexBuffer,GLES30.GL_STATIC_DRAW);//将数据写入VBO
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);//解绑VBO

        }else{
            System.out.println("编译着色器失败");
        }

        GLES30.glClearColor(1,0,0,1f);//设置清空View时的背景色
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0,0,width,height);//绘制的区间
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);//清除颜色缓冲区

        GLES30.glUseProgram(mProgram);//指定当前渲染操作所要使用的着色器程序

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,vboIds[0]);//绑定VBO

        GLES30.glVertexAttribPointer(mPositionHandle, 3, GLES30.GL_FLOAT, false, 5*Float.BYTES, 0);//从VBO中取值并赋值
        GLES30.glVertexAttribPointer(mTextCoordHandle, 2, GLES30.GL_FLOAT, false, 5*Float.BYTES, 3*Float.BYTES);//从VBO中取值并赋值

        GLES30.glUniformMatrix4fv(mTMatrixHandle,1,false,mTranslateMatrix,0);//设置变换矩阵

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);//激活纹理0
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,mTextureId);
        GLES30.glUniform1i(mSamplerHandle,0);//因为我们激活的时纹理0(GLES30.GL_TEXTURE0)，所以第二个参数为0

        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP,0, 4);//渲染，第三个参数为顶点数量
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);//解绑VBO
    }


    private int uploadTexture(){
        Bitmap bitmap = BitmapFactory.decodeResource(APP.getContext().getResources(), R.drawable.background);

        int[] textureIds = new int[1];
        GLES30.glGenTextures(1, textureIds, 0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]);

        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
                GLES30.GL_TEXTURE_MIN_FILTER,
                GLES30.GL_LINEAR);
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
                GLES30.GL_TEXTURE_MAG_FILTER,
                GLES30.GL_LINEAR);

        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D,
                0,
                GLES30.GL_RGBA,
                bitmap,
                0);
        bitmap.recycle();
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
        return textureIds[0];
    }

    public void onDestroy(){
        GLES30.glDeleteBuffers(1,vboIds,0);
        GLES30.glDeleteProgram(mProgram);
    }
}
